########################################################################
# A generic Makefile for C++ programs
#
# Originally Created by Bob Li
# March 14, 2012
########################################################################
#
# Usage:
#
# Synopsis:
#
# make [DEBUG=0|1] [TEST=0|1]
#
# Options:
# Debug=0|1 turns on all debug information [default 0]
#
# Supported Platform: MINGW32, CYGWIN, Linux
#
########################################################################

# System information
SUPPORTED_PLATFORMS := Linux, CYGWIN, MINGW32
export PLATFORM := $(findstring $(shell uname -s | sed 's,_.*,,'),$(SUPPORTED_PLATFORMS))
ifeq ($(PLATFORM),"")
    $(error Unknown platform: $(shell uname -s))
endif
# the top work directory
TOP_WORK_DIR := $(shell pwd)
# case root directory
CASE_DIR := $(TOP_WORK_DIR)/cases
# target name. Usually, only TARGET_NAME need to be changed
TARGET_NAME := dynsp
# include path. Default: .
INCLUDE_DIRS := .
# target path. Default: .
TARGET_PATH := .
# C++ compiler
ifeq ($(PLATFORM),CYGWIN)
    export CC := g++
else
    export CC := g++
endif
# Archieve utility
export AR := ar
export ARFLAGS := rus
# Lexer
export FLEX := flex
export BISON := bison
# case-insensitive parser
export FLEXFLAGS := -i
export BISONFLAGS := --define --yacc

# debug flag. Note: comment out the line below for the release version
ifeq ($(DEBUG),1)
    CONFIG := debug
    export DEBUG_FLAG := -O0 -ggdb -DDEBUG
    export FLEXFLAGS += -d
else
    CONFIG := release
    export DEBUG_FLAG := -O3 -DNDEBUG
endif

# control testing code
ifeq ($(TEST),1)
    export DEBUG_FLAG += -DTEST
endif

# libraries
LDFLAGS := -lm

# all compiler flags
#export CFLAGS := -Wall -Wno-unused-variable $(DEBUG_FLAG)
export CFLAGS := -Wall $(DEBUG_FLAG)

# The excutable has ".exe" suffix on the CYGWIN and MINGW32 platforms.
ifeq ($(PLATFORM),Linux)
    TARGET_SUFFIX :=
else
    TARGET_SUFFIX := .exe
endif
# construct the full target name
TARGET := $(TARGET_PATH)/$(TARGET_NAME)-$(PLATFORM)-$(CONFIG)$(TARGET_SUFFIX)

# the prerequisite of each source file will be generated automatically
# the suffix of source files
export SRCS_SUFFIX := .cpp
# the suffix of rerequisite files
export PREREQ_SUFFIX := .d

SRCS := $(wildcard *$(SRCS_SUFFIX))
OBJS := $(patsubst %$(SRCS_SUFFIX),%.o,$(wildcard *$(SRCS_SUFFIX)))
PREREQS := $(SRCS:%$(SRCS_SUFFIX)=%$(PREREQ_SUFFIX))

# wrapper to run a single case
RUN_SH := $(CASE_DIR)/run.sh
# wrapper to run the whole test suite
RUN_MAKEFILE := $(CASE_DIR)/Makefile

.PHONY: all run test

all: $(TARGET) $(RUN_SH) $(RUN_MAKEFILE)

$(RUN_SH): Makefile
	@echo "Generate $@"
	@$(RM) $(RUN_SH); \
	    echo "#!/bin/sh" > $(RUN_SH); \
	    echo "$(TOP_WORK_DIR)/$(TARGET) \$$1.txt > \$$1.log" >> $(RUN_SH); \
	    chmod +x $(RUN_SH)

$(RUN_MAKEFILE): create_Makefile.pl
	@echo "Generate $@"
	@$(RM) $(RUN_MAKEFILE); \
	    (cd $(CASE_DIR); find -name '*.txt' -type f) > $(CASE_DIR).$$$$; \
	    ./create_Makefile.pl $(CASE_DIR).$$$$ > $(RUN_MAKEFILE); \
	    $(RM) $(CASE_DIR).$$$$

# run all cases
run:
	$(MAKE) --directory=$(CASE_DIR)

# script to test all cases
TEST_T := $(CASE_DIR)/all.t
test:
	(cd $(CASE_DIR); prove -v $(TEST_T))

# avoid always producing the prerequisition lists
ifneq "$(MAKECMDGOALS)" "logclean"
ifneq "$(MAKECMDGOALS)" "test"
ifneq "$(MAKECMDGOALS)" "run"
ifneq "$(MAKECMDGOALS)" "clean"
ifneq "$(MAKECMDGOALS)" "distclean"
    sinclude $(PREREQS)
endif
endif
endif
endif
endif

$(TARGET): $(OBJS)
	@echo "Building $(TARGET) ..."
	$(CC) -o $@ $^ $(LDFLAGS)
	@echo "Successfully build $(TARGET) ."

%$(PREREQ_SUFFIX): %$(SRCS_SUFFIX)
	$(CC) -MM $< $(CFLAGS) $(addprefix -I, $(INCLUDE_DIRS)) > $@.$$$$; \
	sed 's,\($*\)\.o[:]*,\1.o $@:,g' < $@.$$$$ > $@; \
	$(RM) $@.$$$$

%.o: %$(SRCS_SUFFIX)
	$(CC) -c $< -o $@ $(CFLAGS) $(addprefix -I,$(INCLUDE_DIRS))

.PHONY: clean distclean logclean

clean:
	$(RM) $(OBJS) $(PREREQS)

distclean: clean logclean
	$(RM) $(RUN_SH) $(RUN_MAKEFILE)
	$(RM) $(TARGET_PATH)/$(TARGET_NAME)-$(PLATFORM)-*$(TARGET_SUFFIX)

logclean:
	$(MAKE) --directory=$(CASE_DIR) clean
